/**
 * @author Justin Akin
 * @version Action Pals Core Library 0.1.0
 */
package com.actionpals.components.controls
{	
	import flash.display.DisplayObject;
	import flash.display.InteractiveObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	
	/**  
	 * GraphicalSlider adds the ability to skin the track and handle
	 * without interfering with the math involved in a drag.
	 * 
	 * Example:
	 * A track graphic could have a shadow that extends out of the clickable area.
	 * 
	 * Example:
	 * The handle may extend past the defined boundary.
	 */
	public class GraphicalSlider extends SimpleSlider
	{		
	
	//--------------------------------------------------------------------------------
	//
	//	Protected Member variables
	//
	//--------------------------------------------------------------------------------
		
		protected var _handleGraphicContainer:Sprite;
		protected var _trackGraphicContainer:Sprite;
		protected var _handleGraphic:*;
		protected var _trackGraphic:*;
	
	//--------------------------------------------------------------------------------
	//
	//	Constructor
	//
	//--------------------------------------------------------------------------------
	
		/**
		 * Constructor.
		 * 
		 * @param w		The Track used to contain the _handle drag.
		 * @param h		The Handle to be dragged.
		 */
		public function GraphicalSlider( w:Number, h:Number, activeScrollArea:InteractiveObject = null )
		{
			super( w, h, activeScrollArea );			
			init();		
		}
		
	//--------------------------------------------------------------------------------
	//
	//	Public Functions
	//
	//-------------------------------------------------------------------------------- 
		
		public function addHandleGraphic( handleGraphic:DisplayObject ):void
		{	
			_handleGraphic = handleGraphic;
			//_handleGraphic.mouseEnabled = false;
			
			addGraphic( _handleGraphic, _handleGraphicContainer );
			updateHandleGraphic();	
		}
		
		public function addTrackGraphic( trackGraphic:DisplayObject ):void
		{	
			_trackGraphic = trackGraphic;
			//_trackGraphic.mouseEnabled = false;
			
			addGraphic( _trackGraphic, _trackGraphicContainer );
			updateTrackGraphic();
		}
		
	//--------------------------------------------------------------------------------
	//
	//	Getters and Setters
	//
	//--------------------------------------------------------------------------------
		
		public override function set handleWidth( w:Number ):void
		{	
			super.handleWidth = w;
			if( _handleGraphic ) updateHandleGraphic();			
		}
		
		public override function set handleHeight( h:Number ):void
		{	
			super.handleHeight = h;
			if( _handleGraphic ) updateHandleGraphic();	
		}
		
		public override function set trackWidth( w:Number ):void
		{	
			super.trackWidth = w;
			if( _trackGraphic ) updateTrackGraphic();
		}
		
		public override function set trackHeight( h:Number ):void
		{
			super.trackHeight = h;
			if( _trackGraphic ) updateTrackGraphic();
		}
		
	//--------------------------------------------------------------------------------
	//
	//	Protected Functions
	//
	//--------------------------------------------------------------------------------
		
		/**
		 * 
		 */
		protected function init():void
		{
			addContainers();
			configureContainers();
			hideOriginals();
		}
		
		/**
		 * 
		 */
		protected function addContainers():void
		{
			_trackGraphicContainer = addChild( new Sprite() ) as Sprite;
			_handleGraphicContainer = addChild( new Sprite() ) as Sprite;			
		}
		
		
		protected function addGraphic( graphic:DisplayObject, container:Sprite ):void
		{	
			if( container.numChildren > 0 ) container.removeChildAt( 0 );	
			container.addChild( graphic );			
		}
		
		/**
		 * 
		 */
		protected function configureContainers():void
		{
			_handleGraphicContainer.buttonMode = true;
			_handleGraphicContainer.mouseChildren = true;
		}
		
		/**
		 * 
		 */
		protected override function addListeners():void
		{	
			_handleGraphicContainer.addEventListener( MouseEvent.MOUSE_DOWN, onHandleDown );	
			_trackGraphicContainer.addEventListener( MouseEvent.CLICK, onTrackClick );		
			stage.addEventListener( MouseEvent.MOUSE_UP, onMouseEventUp );	
			addEventListener( Event.CHANGE, onUpdate );
		}
		
		/**
		 * 
		 */
		protected function updateHandleGraphic():void
		{	
			var w:Number = _handle.width;
			var h:Number = _handle.height;
			
			if( _handleGraphic )
			{	
				_handleGraphic.width = w;
				_handleGraphic.height = h;
			}
			
			_handleGraphicContainer.x = _handle.x;
			_handleGraphicContainer.y = _handle.y;			
		}
		
		/**
		 * 
		 */
		protected function updateTrackGraphic():void
		{	
			var w:Number = _track.width;
			var h:Number = _track.height;
			
			if( _trackGraphic )
			{	
				_trackGraphic.width = w;
				_trackGraphic.height = h;
			}
			
			_trackGraphicContainer.x = _track.x;
			_trackGraphicContainer.y = _track.y;
		}
		
		/**
		 * 
		 */
		protected function hideOriginals():void
		{	
			_track.alpha = 0;
			_handle.alpha = 0;	
		}
		
		/**
		 * 
		 */
		protected function showOriginals():void
		{
			_track.alpha = 1;
			_track.alpha = 1;
		}
		
	//--------------------------------------------------------------------------------
	//
	//	Event Handlers
	//
	//--------------------------------------------------------------------------------
				
		/**
		 * 
		 */
		protected function onUpdate( event:Event ):void
		{
			updateHandleGraphic();
			updateTrackGraphic();
		}
		
		/**
		 * Called when _track is clicked.  Updates _handle's x and y position.  The closest
		 * side of the _handle is moved to the new position.  For example if you clicked to an
		 * x position that was greater than _handle.x then _handle's right side would be aligned
		 * with the new x position.
		 * 
		 * @param event		An Event object.
		 */
		protected override function onTrackClick( event:MouseEvent ):void
		{	
			var temp:Rectangle = _handle.getRect( this );
			var xPos:Number = event.localX;
			var yPos:Number = event.localY;
			
			if( xPos > temp.x ) xPos -= temp.width;
			if( yPos > temp.y ) yPos -= temp.height;
			
			updateHandle( xPos, yPos );
		}
		
		/**
		 * Called when _handle is pressed down.  Allows _handle to drag within _track's area.
		 * 
		 * @param event		An Event object.
		 */
		protected override function onHandleDown( event:MouseEvent ):void
		{	
			_dragManager.remove( _handleGraphicContainer );
			_dragManager.add( _handleGraphicContainer, _track.getBounds( this ) );
			
			stage.addEventListener( MouseEvent.MOUSE_MOVE, onHandleMove );
			stage.addEventListener( Event.MOUSE_LEAVE, onMouseLeave );
			stage.addEventListener( MouseEvent.MOUSE_UP, onMouseEventUp );	
		}
		
		/**
		 * Called when _handle is dragged.  Calls dispatchUpdate.
		 * 
		 * @param event		An Event object.
		 */
		protected override function onHandleMove( event:MouseEvent ):void
		{	
			if( event.buttonDown )
			{
				updateHandle( _handleGraphicContainer.x, _handleGraphicContainer.y );
				dispatchUpdate();
			}
			else
			{
				_dragManager.remove( _handleGraphicContainer );
				
				stage.addEventListener( MouseEvent.MOUSE_MOVE, onHandleMove );
				stage.addEventListener( Event.MOUSE_LEAVE, onMouseLeave );
				stage.addEventListener( MouseEvent.MOUSE_UP, onMouseEventUp );	
			}			
		}				
	}
}